1.为什么要使用并发,并发带来好处的同时有什么风险?

您所在的位置:网站首页 事务 并发 1.为什么要使用并发,并发带来好处的同时有什么风险?

1.为什么要使用并发,并发带来好处的同时有什么风险?

2024-07-05 15:39| 来源: 网络整理| 查看: 265

第一章 概述 1.串行,并行和并发

什么是并发?在了解并发前我们引入并行和串行的例子来对比,让我们更好的理解并发。

1.串行是指两个或两个以上程序按顺序发生 2.并行是指两个或以上程序在同一时间点发生 3.并发是指两个或两个以上程序在同一时间段发生 通俗一点就是你打游戏打到一半你妈妈叫你吃饭了,你打完游戏再去吃饭,这就是串行一件一件事情完成。如果你手速够快你可以放个技能吃口饭推个塔吃口饭,在游戏和吃饭之间来回切换丝毫不影响你送人头这就是并发。再如果你是大神一只手操作另一只手吃饭同时进行不耽误你carry队友这就是并行。 在这里插入图片描述 在单cpu系统中,每一时间点只能有一道程序执行,即微观上这些程序是分时的交替执行,因为分时交替运行的时间是非常短的,只不过给人的感觉是同时运行,在宏观上并发和并行一样都是同时在进行但是在微观上是不一样的。在多个cpu的操作系统中,这些可以并发执行的程序便可以分配到多个处理器(cpu),实现多任务并行执行,就是利用每个处理器来处理一个可以并发执行的程序,这样多个程序便可以同时执行。核越多,并行处理的程序越多,可以大大提高电脑的运行效率。如果能够合理地使用多线程,将能够缩减复杂应用程序的开发和维护成本,并能提供更好的性能。通过将异步工作流转换为多个序列化工作流,多线程可以更好地对人类的工作和交互方式建模。使用多线程,很多复杂的代码将变得更加直截了当,因此更容易编写、阅读和维护,但是使用多线程也意味着有很大的风险。

2.风险 2.1安全风险

线程安全问题可能变得意想不到地微妙,因为在缺少合理的同步机制的情况下,多线程的执行顺序是不 可预知的,有时甚至是令人惊讶的。下面的程序本来想产生一列无重复的整数值,在单线程环境中运行正常,在多线程环境中却运行失败。这个程序演示了多线程交错运行可能导致出乎意料的结果。

/** * 用于实现输出一个无重复的整数序列的类 * * 该类不是线程安全的 */ @NotThreadSafe public class UnsafeSequence { private int value; public int getNext() { return value++; } }

上例在多线程环境中失败的原因是,在某些时候,两个线程调用 getNext()方法的时刻非常接近,以至于返回的是同一个数值。value++看似是一个操作,实质上是三个操作:读取 value 值,value 值加 1,重设 value 值。由于多个线程中的操作可以任意地交错,可能出现两个线程获得的是相同数值的 value,然后各自都加 1 的情况。下图形象地说明了这一点:

在这里插入图片描述 这个例子演示了一种常见的并发风险,叫做竞争条件。nextValue()方法是否返回一列无重复的整数值取决于多线程在运行时的交错情况,这种不确定性不是我们希望看到的。由于多线程共享同样的内存空间,并且并发执行,它们可以访问和修改其他线程正在使用的变量。这样非常方便,相比于其他线程间通信机制,共享变量更简单。但共享变量也有极大的风险。数据可能会以不希望的方式被修改掉,导致一些很难找出原因的 Bug。为了让多线程程序的行为具有可预测性,共享变量的访问必须被合理地协调,使得一个线程对该变量的访问不会干扰到另一个线程。

2.2活跃性风险

在开发并发程序的时候一定要注意线程安全问题,线程安全性是不能妥协的。不仅多线程程序需要注意安全性,单线程程序也需要注意安全性和正确性,但是多线程引入了额外的安全风险。相似地,多线程引入了活跃性故障,这在单线程程序中是不存在的。当一个活动到达了无法前进的状态的时候,活跃性故障就发生了。在单线程程序中有一种活跃性故障是由无限循环造成的,导致循环之后的代码永远无法被执行。多线程的引入,增加了活跃性故障发生的可能性。例如线程 A 在等待一个 资源,该资源被线程 B 排他性地占有了,并且线程 B 永远不释放该资源,那么线程 A 必须永远等待下去。这就是一种活跃性故障。由活跃性故障引起的 Bug 往往难以锁定,因为它们依赖于不同线程中,事件发生的相对时机。因此在开发和测试过程中这种 Bug 会时隐时现。

2.3性能风险

性能问题包含一大堆其他问题,包括响应速度、吞吐量、资源消耗量和可伸缩性。就像安全性和活跃性一样,多线程程序不仅要面对单线程程序中所有的性能风险,还要面对由多线程引入的性能风险。在设计良好的并发程序中,多线程的使用可以提高性能,但是多线程会增加运行时开销。在多线程程序中调度器经常需要临时挂起一个线程,运行另一个线程,这被称为上下文切换。上下文切换会造成很大的开销,保存和恢复执行上下文、调度线程都需要时间。线程间的同步机制将会阻碍编译器对代码的优化、阻止内存缓冲区的清空和验证,这些因素都会降低多线程程序的性能。

结束语:

编写正确的程序很难,编写正确的并发程序更难。为什么要使用并发呢?在Java 编程中你免不了要使用并发特性,在一些复杂系统的开发中使用并发使你能够将一些复杂的计算过程以最直接的方式用代码表现出来。此外,并发程能够有效利用多核处理器的计算能力,随着计算机系统中处理器数量的增加,研究如何有效地编写 Java 并发程序变得非常重要。

参考:SpringForAll社区公众号(微信号spring4all)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3